package com.tj.collection.filters;

import com.fqgj.log.factory.LogFactory;
import com.fqgj.log.interfaces.Log;
import com.fqgj.log.util.Constants;
import com.robert.vesta.util.IdUtils;
import org.apache.logging.log4j.ThreadContext;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

@Component
@WebFilter(urlPatterns = "/*", filterName = "corsFilter")
public class CrosFilter extends OncePerRequestFilter {

    private static final Log LOGGER = LogFactory.getLog(CrosFilter.class);

    public static final Set<String> ALLOWED_PATHS = new HashSet<>(
            Arrays.asList("/bizStats/general/export",
                    "/message/collection/send",
                    "/message/collection/push",
                    "/export",
                    "/upload",
                    "favicon.ico",
                    "/error"
            )
    );

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {
            response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
            response.setHeader("Access-Control-Allow-Credentials", "true");
            response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
            response.setHeader("Access-Control-Max-Age", "3600");
            response.setHeader("Access-Control-Allow-Headers", "Content-Type,Accept,X-Requested-With,remember-me,bid,accessToken,productCategory,appCode");
        }
        if ("OPTIONS".equals(request.getMethod())) {
            filterChain.doFilter(request, response);
            return;
        }
        String requestURI = request.getRequestURI();

        for (String s : ALLOWED_PATHS) {
            if (requestURI.toLowerCase().contains(s)) {
                LOGGER.info("过滤器放行,url:{}", requestURI);
                filterChain.doFilter(request, response);
                return;
            }
        }

        Long startTime = System.currentTimeMillis();
        String traceId = IdUtils.genId() + "";
        ThreadContext.put(Constants.TRACE_ID, traceId);

        String accessToken = request.getHeader("accessToken");
        String basicParams = request.getHeader("basicParams");
        String productCategory = request.getHeader("productCategory");
        String domainHost = request.getHeader("Host");

        RequestWrapper requestWrapper = new RequestWrapper(request);
        ResponseWrapper responseWrapper = new ResponseWrapper(response);

        try {
            filterChain.doFilter(requestWrapper, responseWrapper);
            String responseBody = new String(responseWrapper.getResponseData());

            //解决可能在运行的过程中页面只输出一部分
            response.setContentLength(-1);
            PrintWriter out = response.getWriter();
            out.write(responseBody);
            out.flush();
            out.close();

            BufferedReader bufferedReader = requestWrapper.getReader();
            String line;
            StringBuilder requestBody = new StringBuilder();
            while ((line = bufferedReader.readLine()) != null) {
                requestBody.append(line);
            }
            Long costTime = System.currentTimeMillis() - startTime;
            if (basicParams != null && basicParams.contains("web")) {
                LOGGER.info("admin过滤器日志1,TraceId:{},token:{},method:{},host:{},url:{},productCategory:{},basicParams:{},cost:{},request:{},response:{}",
                        traceId, accessToken, request.getMethod(), domainHost, requestURI, productCategory, basicParams, costTime,
                        requestBody,
                        (responseBody.length() > 4096 ? ("responseSize:" + responseBody.length()) : responseBody)
                );
            } else {
                LOGGER.info("admin过滤器日志2,TraceId:{},token:{},method:{},host:{},url:{},productCategory:{},basicParams:{},cost:{},request:{},response:{}",
                        traceId, accessToken, request.getMethod(), domainHost, requestURI, productCategory, basicParams, costTime,
                        requestBody,
                        (responseBody.length() > 4096 ? ("responseSize:" + responseBody.length()) : responseBody)
                );
            }
        } catch (Exception e) {
            BufferedReader bufferedReader = requestWrapper.getReader();
            String line;
            StringBuilder requestBody = new StringBuilder();
            while ((line = bufferedReader.readLine()) != null) {
                requestBody.append(line);
            }
            LOGGER.error("admin过滤器异常日志,TraceId:{},token:{},method:{},url:{},basicParams:{},request:{}",
                    traceId, accessToken, request.getMethod(), requestURI, basicParams, requestBody, e);
            throw e;
        } finally {
            ThreadContext.clearAll();
        }
    }
}
